#ifndef COMMANDS_H
#define COMMANDS_H

#include <QUndoCommand>
#include "glwidget.h"

//This file realized redo&undo framework of Qt based on QUndoCommand class.

//!  An add object class.
/*!
  When user adds an object to the scene, construct an instance of this class to construct a new object.
*/
class AddObjectCommand:public QUndoCommand
{
public:
    AddObjectCommand(GLWidget *_glWidget, int _objectType, QUndoCommand *parent = 0);
    ~AddObjectCommand();
    void undo();
    void redo();

private:
    //! Store the pointer of the GLWidget.
    GLWidget *glWidget;

    //! Store the pointer of the added object.
    CellObject *object;
};

//! A delete object class
/*!
  When a user deletes an object from the scene, construct an instance of this class to delete the object.
  */
class DeleteObjectCommand:public QUndoCommand
{
public:
    DeleteObjectCommand(GLWidget * _glWidget, int _index, QUndoCommand *parent = 0);
    ~DeleteObjectCommand();
    void undo();
    void redo();

private:
    //! Store the pointer of the GLWidget.
    GLWidget *glWidget;

    //! Store the pointer of the object.
    CellObject *object;

    //! Store the index of the object
    int index;

};



//!  A class realized union operation.
/*!
  When user unions two objects, will construct this class to do the union operation.
 */
class UnionCommand:public QUndoCommand
{
public:
    UnionCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent = 0);
    ~UnionCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the index of the first object.
    int firstIndex;

    //! Store the index of the second object.
    int secondIndex;

    //! Store the pointer of the first object.
    CellObject *firstObject;

    //! Store the pointer of the second object.
    CellObject *secondObject;

    //! Store the pointer of the result object.
    CellObject *resultObject;
};

//!  A class realized intersection operation.
/*!
  When user intersects two objects, will construct this class to do the intersection operation.
*/
class IntersectCommand:public QUndoCommand
{
public:
    IntersectCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent = 0);
    ~IntersectCommand();
    void undo();
    void redo();

private:
    //! Store the pointer of GLWidget.
    GLWidget *glWidget;

    //! Store the index of the first object.
    int firstIndex;

    //! Store the index of the second object.
    int secondIndex;

    //! Store the pointer of the first object.
    CellObject *firstObject;

    //! Store the pointer of the second object.
    CellObject *secondObject;

    //! Store the pointer of the result object.
    CellObject *resultObject;
};

//!  A class realized subtration operation.
/*!
  When user subtracts one object from another object, will construct this class to do the subtration operation.
*/
class SubtractCommand:public QUndoCommand
{
public:
    SubtractCommand(GLWidget *_glWidget, int _firstIndex, int _secondIndex, QUndoCommand *parent = 0);
    ~SubtractCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the index of the first object.
    int firstIndex;

    //! Store the index of the second object.
    int secondIndex;

    //! Store the pointer of the first object.
    CellObject *firstObject;

    //! Store the pointer of the second object.
    CellObject *secondObject;

    //! Store the pointer of the result object.
    CellObject *resultObject;
};

//!  A class translated object.
/*!
  When user translates a object by mouse drag or type value in object imformation widget, will construct this class to translate the object.
*/
class TranslateCommand:public QUndoCommand
{
public:
    TranslateCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                     double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent = 0);
    ~TranslateCommand();
    void undo();
    void redo();

    //! Call this function when mouse released.
    void setNew(double _newX, double _newY, double _newZ);

private:
    //! Store the pointer of GLWidget.
    GLWidget *glWidget;

    //! Store the old value x of translated object. Record it when mouse pressed.
    double oldX;

    //! Store the old value y of translated object. Record it when mouse pressed.
    double oldY;

    //! Store the old value z of translated object. Record it when mouse pressed.
    double oldZ;

    //! Store the new value x of translated object. Update it when mouse released.
    double newX;

    //! Store the new value y of translated object. Update it when mouse released.
    double newY;

    //! Store the new value z of translated object. Update it when mouse released.
    double newZ;

    //! Store the index of translated object.
    int index;
};

//!  A class rotated object.
/*!
  When user rotates a object by mouse drag or type value in object imformation widget, will construct this class to rotate the object.
*/
class RotateCommand:public QUndoCommand
{
public:
    RotateCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                     double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent = 0);
    ~RotateCommand();
    void undo();
    void redo();

    //! Call this function when mouse released.
    void setNew(double _newX, double _newY, double _newZ);

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the old value x of rotated object. Record it when mouse pressed.
    double oldX;

    //! Store the old value y of rotated object. Record it when mouse pressed.
    double oldY;

    //! Store the old value z of rotated object. Record it when mouse pressed.
    double oldZ;

    //! Store the new value x of rotated object. Update it when mouse released.
    double newX;

    //! Store the new value y of rotated object. Update it when mouse released.
    double newY;

    //! Store the new value z of rotated object. Update it when mouse released.
    double newZ;

    //! Store the index of rotated object.
    int index;
};

//!  A class scaled object.
/*!
  When user scales a object by mouse drag or type value in object imformation widget, will construct this class to scale the object.
*/
class ScaleCommand:public QUndoCommand
{
public:
    ScaleCommand(GLWidget *_glWidget, double _oldX, double _oldY, double _oldZ,
                     double _newX, double _newY, double _newZ, int _index, QUndoCommand *parent = 0);
    ~ScaleCommand();
    void undo();
    void redo();

    //! Call this function when mouse released.
    void setNew(double _newX, double _newY, double _newZ);

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the old value x of scaled object. Record it when mouse pressed.
    double oldX;

    //! Store the old value y of scaled object. Record it when mouse pressed.
    double oldY;

    //! Store the old value z of scaled object. Record it when mouse pressed.
    double oldZ;

    //! Store the new value x of scaled object. Update it when mouse released.
    double newX;

    //! Store the new value y of scaled object. Update it when mouse released.
    double newY;

    //! Store the new value z of scaled object. Update it when mouse released.
    double newZ;

    //! Store the index of scaled object.
    int index;
};

//!  A class added a sphere to the scene.
/*!
  When user adds a sphere to the scene, will construct this class.
*/
class SphereInputCommand:public QUndoCommand
{
public:
    SphereInputCommand(GLWidget *_glWidget, CellObject *_obj,
                       double _oldRadius, int _oldHeightSeg, int _oldAxisSeg,
                       double _newRadius, int _newHeightSeg, int _newAxisSeg, QUndoCommand *parent = 0);
    ~SphereInputCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the point of the modified object.
    CellObject *object;

    //! Store the old radius value of the object.
    double oldRadius;

    //! Store the old height segmentation value of the object.
    int oldHeightSeg;

    //! Store the old axis segmentation value of the object.
    int oldAxisSeg;

    //! Store the new radius value of the object.
    double newRadius;

    //! Store the new height segmentation value of the object.
    int newHeightSeg;

    //! Store the new axis segmentation value of the object.
    int newAxisSeg;
};

//!  A class added a cylinder or an open cylinder to the scene.
/*!
  When user adds a cylinder or an open cylinder to the scene, will construct this class.
*/
class CylinderInputCommand:public QUndoCommand
{
public:
    CylinderInputCommand(GLWidget *_glWidget, CellObject *_obj,
                         double _oldRadius, double _oldHeight, int _oldHeightSeg, int _oldAxisSeg,
                         double _newRadius, double _newHeight, int _newHeightSeg, int _newAxisSeg, int _type, QUndoCommand *parent = 0);
    ~CylinderInputCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the point of the modified object.
    CellObject *object;

    //! Store the old radius value of the object.
    double oldRadius;

    //! Store the old height value of the object.
    double oldHeight;

    //! Store the old height segmentation value of the object.
    int oldHeightSeg;

    //! Store the old axis segmentation value of the object.
    int oldAxisSeg;

    //! Store the new radius value of the object.
    double newRadius;

    //! Store the new height value of the object.
    double newHeight;

    //! Store the new height segmentation value of the object.
    int newHeightSeg;

    //! Store the new axis segmentation value of the object.
    int newAxisSeg;

    //! Store the type of the cylinder, the value can be CELL_CYLINDER or CELL_OPENCYLINDER.
    int type;
};

//!  A class added a cube to the scene.
/*!
  When user adds a cube to the scene, will construct this class.
*/
class CubeInputCommand:public QUndoCommand
{
public:
    CubeInputCommand(GLWidget *_glWidget, CellObject *_obj,
                     double _oldWidth, double _oldHeight, double _oldDepth,
                     int _oldWidthSeg, int _oldHeightSeg, int _oldDepthSeg,
                     double _newWidth, double _newHeight, double _newDepth,
                     int _newWidthSeg, int _newHeightSeg, int _newDepthSeg, QUndoCommand *parent = 0);
    ~CubeInputCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the point of the modified object.
    CellObject *object;

    //! Store the old width value of the object.
    double oldWidth;

    //! Store the old height value of the object.
    double oldHeight;

    //! Store the old depth value of the object.
    double oldDepth;

    //! Store the old width segmentation value of the object.
    int oldWidthSeg;

    //! Store the old height segmentation value of the object.
    int oldHeightSeg;

    //! Store the old depth segmentation value of the object.
    int oldDepthSeg;

    //! Store the new width value of the object.
    double newWidth;

    //! Store the new height value of the object.
    double newHeight;

    //! Store the new depth value of the object.
    double newDepth;

    //! Store the new width segmentation value of the object.
    int newWidthSeg;

    //! Store the new height segmentation value of the object.
    int newHeightSeg;

    //! Store the new depth segmentation value of the object.
    int newDepthSeg;
};

//!  A class selected a differant object.
/*!
  When user selects a different object, will construct this class.
*/
class SelectObjectCommand:public QUndoCommand
{
public:
    SelectObjectCommand(GLWidget *_glWidget, int _lastSelectObject, QUndoCommand *parent = 0);
    ~SelectObjectCommand();
    void setRecSelectObject(int s);
    bool isSelectChanged();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the index of the last selected object.
    int lastSelectObject;

    //! Store the index of the selected object at the moment.
    int recSelectObject;
};

//!  A class realized the mesh changed command.
/*!
  When user modifies the mesh, will construct this class.
*/
class MeshChangedCommand:public QUndoCommand
{
public:
    MeshChangedCommand(GLWidget *_glWidget, CellObject *_unchangedObject, int _index, QUndoCommand *parent = 0);
    ~MeshChangedCommand();
    void undo();
    void redo();

private:
    //! Store the point of GLWidget.
    GLWidget *glWidget;

    //! Store the point of the unmodified object.
    CellObject *unchangedObject;

    //! Store the point of the object after modified.
    CellObject *changedObject;

    //! Store the index of the object.
    int index;
};

#endif // COMMANDS_H
